home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1994 / MacHack 1994.toast / MacHack™94 / Miscellaneous / Randy Thelen / ThreadedBrot / Lib / DialogUtils.cp < prev    next >
Encoding:
Text File  |  1994-06-26  |  7.9 KB  |  316 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        DialogUtils.cp
  3.  
  4.     Contains:    Auto-sized error alert mechanism,
  5.                 ModalFilterProcs which correctly handle events,
  6.                 and Standard “Close Document” dialogs. 
  7.  
  8.     Written by: Dave Falkenburg
  9.  
  10.     Copyright:    © 1993-94 by Dave Falkenburg, all rights reserved.
  11.  
  12.     Change History (most recent first):
  13.      
  14.  */
  15.  
  16. #include <Types.h>
  17. #include <Memory.h>
  18. #include <Quickdraw.h>
  19. #include <Fonts.h>
  20. #include <Resources.h>
  21. #include <Windows.h>
  22. #include <Dialogs.h>
  23. #include <Threads.h>        //    For YieldToAnyThread()
  24. #include <TextUtils.h>        //    For StdFilterProc()
  25. #include <StandardFile.h>    //    For ModalFilterYDProcPtr
  26.  
  27. #include "AppLib.h"
  28.  
  29.  
  30. //    Some types which should probably be defined in <Dialogs.h>
  31. //    (but aren’t because somebody doesn’t want to support them?)
  32. //
  33. //    NOTE: These must be aligned on 2-byte boundaries
  34.  
  35. #if defined(powerc) || defined (__powerc)
  36. #pragma options align=mac68k
  37. #endif
  38.  
  39. struct DialogItem
  40.     {
  41.     long    usedByDialogManager;
  42.     Rect    boundsRect;
  43.     char    type;
  44.     char    length;
  45.     };
  46.  
  47. struct DialogItemList            //    a.k.a. a 'DITL'
  48.     {
  49.     short        count;
  50.     DialogItem    firstItem[1];
  51.     };
  52.  
  53. //    Restore default alignment
  54.  
  55. #if defined(powerc) || defined(__powerc)
  56. #pragma options align=reset
  57. #endif
  58.  
  59. typedef    DialogItem        *DialogItemPtr;
  60. typedef    DialogItemList    **DialogItemListHandle;
  61. typedef    AlertTemplate    **AlertTemplateHandle;
  62.  
  63.  
  64. //    private function Prototypes
  65.  
  66. static    pascal Boolean    StandardDialogFilterProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  67. static    pascal Boolean    StandardDialogFilterYDProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit, void * yourData);
  68. static    Boolean            FilterProcCommon(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  69.  
  70.  
  71.  
  72. ///////////////////////////////////////////////////////////
  73. //
  74. //    StandardAlert
  75. //
  76. //    An alternative to Alert() which uses the extended
  77. //    Dialog Manager capabilities.
  78. //
  79. //    I’m not sure we really need this call, but it seems
  80. //    to do the trick just fine.
  81.  
  82. short
  83. StandardAlert(short alertID)
  84.     {
  85.     DialogPtr    theDialog;
  86.     short        itemHit = 0;
  87.     
  88.     HiliteWindowsForModalDialog(false);
  89.  
  90.     theDialog = GetNewDialog(alertID,nil,(WindowPtr) -1);
  91.     SetDialogDefaultItem(theDialog,ok);
  92.  
  93.     do
  94.         ModalDialog(StandardDialogFilter,&itemHit);
  95.     while (itemHit == 0);
  96.     
  97.     DisposeDialog(theDialog);
  98.  
  99.     HiliteWindowsForModalDialog(true);
  100.  
  101.     return itemHit;
  102.     }
  103.  
  104.  
  105. ///////////////////////////////////////////////////////////
  106. //
  107. //    ErrorAlert
  108. //
  109. //    A nice error reporting routine which presents an
  110. //    auto-sized alert box containing the supplied text.
  111. //
  112. //    NOTE:    This routine ASSUMES the following 'DITL'
  113. //            structure:
  114. //
  115. //            item #1 : an “OK” button
  116. //            item #2 : a static text item, somewhere above #1
  117. //
  118. //    NOTE:    We probably need to worry more about low
  119. //            memory conditions-- this can probably
  120. //            be handled by a custom GrowZoneProc and
  121. //            reserve memory area large enough to hold
  122. //            all the space we’d need.
  123. //
  124.  
  125. void
  126. ErrorAlert(short stringList,short whichString)
  127.     {
  128.     Str255                    errorString;
  129.     GrafPtr                    oldPort,windowMgrPort;
  130.     short                    oldFont;
  131.     AlertTemplateHandle        errorAlertTemplate;
  132.     DialogItemListHandle    errorAlertItems;
  133.     TEHandle                aTEHandle;
  134.     Rect                    textRect;
  135.     short                    textHeight;
  136.     short                    additionalSpaceNeeded;
  137.     DialogItemPtr            okButtonItem,errorTextItem;
  138.     const StringPtr            nullStr = (StringPtr) "\p";
  139.  
  140.     GetIndString(errorString,stringList,whichString);
  141.     
  142.     errorAlertTemplate = (AlertTemplateHandle) Get1Resource('ALRT',kErrorAlertID);
  143.     HLock((Handle) errorAlertTemplate);
  144.     
  145.     errorAlertItems = (DialogItemListHandle) Get1Resource('DITL',(**errorAlertTemplate).itemsID);
  146.     HLock((Handle) errorAlertItems);
  147.     
  148.     //    Find the dialog items
  149.     
  150.     okButtonItem = (**errorAlertItems).firstItem;
  151.     errorTextItem = (DialogItemPtr) ((Ptr) okButtonItem + sizeof(DialogItem) + okButtonItem->length);
  152.     
  153.     GetPort(&oldPort);
  154.     GetWMgrPort(&windowMgrPort);
  155.     SetPort(windowMgrPort);
  156.     oldFont = qd.thePort->txFont;
  157.     TextFont(systemFont);
  158.  
  159.     aTEHandle = TENew(&textRect,&textRect);
  160.     TESetText(&errorString[1],errorString[0],aTEHandle);
  161.     textHeight = (*aTEHandle)->lineHeight * (*aTEHandle)->nLines;
  162.     TEDispose(aTEHandle);
  163.  
  164.     additionalSpaceNeeded = textHeight - (errorTextItem->boundsRect.bottom
  165.                             - errorTextItem->boundsRect.top);
  166.  
  167.     if (additionalSpaceNeeded > 0)
  168.         {
  169.         (**errorAlertTemplate).boundsRect.bottom += additionalSpaceNeeded;
  170.         errorTextItem->boundsRect.bottom += additionalSpaceNeeded;
  171.         OffsetRect(&okButtonItem->boundsRect,0,additionalSpaceNeeded);
  172.         }
  173.         
  174.     TextFont(oldFont);
  175.     SetPort(oldPort);
  176.     
  177.     InitCursor();
  178.     ParamText(errorString,nullStr,nullStr,nullStr);
  179.  
  180.     (void) StandardAlert(kErrorAlertID);
  181.  
  182.     ReleaseResource((Handle) errorAlertTemplate);
  183.     ReleaseResource((Handle) errorAlertItems);
  184.     }
  185.  
  186.  
  187. ///////////////////////////////////////////////////////////
  188. //
  189. //    FatalErrorAlert
  190. //
  191. //    A companion to ErrorAlert which also kills the process.
  192. //
  193.  
  194. void
  195. FatalErrorAlert(short stringList,short whichString)
  196.     {
  197.     ErrorAlert(stringList,whichString);
  198.     ExitToShell();
  199.     }
  200.  
  201.  
  202. ///////////////////////////////////////////////////////////
  203. //
  204. //    StandardDialogFilter and StandardDialogFilterYD
  205. //
  206. //    These function takes care of routing events not meant
  207. //    for the dialog window to other parts of the application.
  208. //
  209. //    Use them as an alternative to passing a NIL ModalFilterProc
  210. //    to ModalDialog() and CustomGet(Put)File. Unlike the default
  211. //    filter, these routines properly processes update events
  212. //    to keep background processes running.
  213. //
  214. //    The Thread Manager, if present, is also called to yield
  215. //    control to other cooperative threads within the process.
  216. //
  217. //    Because of pascal calling conventions we need two separate
  218. //    routines, but this is minimized by sharing implementation
  219. //    in FilterProcCommon.
  220. //
  221.  
  222. ModalFilterUPP    StandardDialogFilter
  223. = NewModalFilterProc(StandardDialogFilterProc);
  224.  
  225. ModalFilterYDUPP    StandardDialogFilterYD
  226. = NewModalFilterYDProc(StandardDialogFilterYDProc);
  227.  
  228.  
  229. pascal Boolean
  230. StandardDialogFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  231.     {
  232.     //    Call through common code to check for events we’d like to handle.
  233.     //    If that is unsuccessful, call through the System 7 StdFilterProc
  234.     //    to handle CR, “CMD-.” & ESC in an international-friendly manner.
  235.  
  236.     if (FilterProcCommon(theDialog, anEvent, itemHit))
  237.         return true;
  238.     else
  239.         return (StdFilterProc(theDialog, anEvent, itemHit));
  240.     }
  241.  
  242.  
  243. pascal Boolean
  244. StandardDialogFilterYDProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit, void * /*unusedData*/)
  245.     {
  246.     //    We don’t call through to StdFilterProc since the
  247.     //    Standard File Package already does everything we need.
  248.  
  249.     return FilterProcCommon(theDialog, anEvent, itemHit);
  250.     }
  251.  
  252.  
  253. Boolean
  254. FilterProcCommon(DialogPtr theDialog, EventRecord * anEvent, short * /* itemHit */)
  255.     {
  256.     switch (anEvent->what)
  257.         {
  258.         case updateEvt:
  259.         case activateEvt:
  260.             //     Update or activate for the dialog window?
  261.             if (theDialog == (DialogPtr) anEvent->message)
  262.                 break;
  263.  
  264.             //    no, fall through to HandleEvent            
  265.             
  266.         case diskEvt:
  267.             HandleEvent(anEvent);
  268.             return(false);
  269.  
  270.         default:
  271.             break;        
  272.         }
  273.  
  274.     if (gHasThreadManager)        //    If we have threads, let them run!
  275.         YieldToAnyThread();
  276.  
  277.     return false;                //    We didn’t handle the event
  278.     }
  279.  
  280.  
  281. //////////////////////////////////////////////////////////////////
  282. //
  283. //    StandardCloseDocument
  284. //
  285. //    Provides the standard human interface for closing a document
  286. //
  287. //    NOTE: When we make TDocument class, this will become a method
  288. //          and probably won’t need any parameters.
  289. //
  290. //    NOTE:    StandardCloseResult matches the dialog items for 
  291.  
  292. StandardCloseResult
  293. StandardCloseDocument(const StringPtr documentType, StringPtr documentName,
  294.                       Boolean hasNewEditions, Boolean quitting)
  295.     {
  296.     short        whichAlert;
  297.     short        whichString;
  298.     StringPtr    nullStr = (StringPtr) "\p";
  299.     Str255        reasonForClosingStr;
  300.  
  301.     if (hasNewEditions)
  302.         whichAlert = kStandardCloseWithNewPubsAlertID;
  303.     else
  304.         whichAlert = kStandardCloseAlertID;
  305.     
  306.     if (quitting)
  307.         whichString = kQuittingStr;
  308.     else
  309.         whichString = kClosingStr;
  310.  
  311.     GetIndString(reasonForClosingStr,kStandardCloseStrings,whichString);
  312.     ParamText(documentType,documentName,reasonForClosingStr,nullStr);
  313.     
  314.     return ((StandardCloseResult) StandardAlert(whichAlert));
  315.     }
  316.